package toolfunc

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	md "github.com/JohannesKaufmann/html-to-markdown"
	"github.com/shopspring/decimal"
	"gorm.io/gorm"
	"html/template"
	"math"
	"math/rand"
	"reflect"
	"time"
	"unicode"

	"strconv"

	"io"
	"net/url"
	"os"
	"strings"

	"io/ioutil"
	"regexp"
	"sort"
)

// 将interface类型的数据转化成 string
func Strval(value interface{}) interface{} {
	// interface 转 string
	var key string
	if value == nil {
		return gorm.Expr("NULL")
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	case time.Time:
		key = value.(time.Time).Format("2006-01-02 15:04:05")
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}
	return key
}

func CheckInterface(inter interface{}) {

	switch inter.(type) {

	case string:
		fmt.Println("string", inter.(string))
		break
	case int:
		fmt.Println("int", inter.(int))
		break
	case float64:
		fmt.Println("float64", inter.(float64))
		break
	}

}
func CheckFileIsExist(filename string) bool {
	var exist = true
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		exist = false
	}
	return exist
}
func BubbleSortPro(arr []int64) []int64 {
	length := len(arr)
	for i := 0; i < length; i++ {
		over := false
		for j := 0; j < length-i-1; j++ {
			if arr[j] > arr[j+1] {
				over = true
				arr[j], arr[j+1] = arr[j+1], arr[j]
			}
		}
		if over == false {
			break
		}
	}
	return arr
}
func GetDays(start, end int64) (timeSilce []string) {
	startTime := time.Unix(start, 0)
	endTime := time.Unix(end, 0)
	sub := int(endTime.Sub(startTime).Hours())
	days := sub / 24
	if (sub % 24) > 0 {
		days = days + 1
	}

	for i := days; i > 0; i-- {
		timeSilce = append(timeSilce, time.Now().AddDate(0, 0, -i).Format("2006-01-02"))
	}

	return
}
func GetDuration(start, end int64) int {
	startTime := time.Unix(start, 0)
	endTime := time.Unix(end, 0)
	sub := int(endTime.Sub(startTime).Hours())
	days := sub / 24
	if (sub % 24) > 0 {
		days = days + 1
	}

	return days
}
func RemoveDuplicateIntElement(addrs []int) []int {
	result := make([]int, 0, len(addrs))
	temp := map[int]struct{}{}
	for _, item := range addrs {
		if _, ok := temp[item]; !ok {
			temp[item] = struct{}{}
			result = append(result, item)
		}
	}
	return result
}

func RemoveDuplicateUintElement(addrs []uint) []uint {
	result := make([]uint, 0, len(addrs))
	temp := map[uint]struct{}{}
	for _, item := range addrs {
		if _, ok := temp[item]; !ok {
			temp[item] = struct{}{}
			result = append(result, item)
		}
	}
	return result
}

func RemoveDuplicateElement(addrs []string) []string {
	result := make([]string, 0, len(addrs))
	temp := map[string]struct{}{}
	for _, item := range addrs {
		if _, ok := temp[item]; !ok {
			temp[item] = struct{}{}
			if item != "" {
				result = append(result, item)
			}

		}
	}
	return result
}

func UniqueSort(slice []int64) []int64 {
	res := make([]int64, 0)
	mp := make(map[int64]bool, len(slice))
	for _, e := range slice {
		if mp[e] == false {
			mp[e] = true
			res = append(res, e)
		}
	}
	return BubbleSortPro(res)
}

func StringIn(target string, str_array []string) bool {
	sort.Strings(str_array)
	index := sort.SearchStrings(str_array, target)
	//index的取值：[0,len(str_array)]
	if index < len(str_array) && str_array[index] == target { //需要注意此处的判断，先判断 &&左侧的条件，如果不满足则结束此处判断，不会再进行右侧的判断
		return true
	}
	return false
}

// 比较两个内容的字符串类型是否相等
func Equal(itf1, itf2 interface{}) bool {
	return fmt.Sprintf("%v", itf1) == fmt.Sprintf("%v", itf2)
}

// xmd5加密，扩展加密
//
//	md5str          MD5字符串
func Xmd5(md5str interface{}) string {
	return fmt.Sprintf("%v", md5str)
}
func Struct2Map(obj interface{}) map[string]interface{} {
	t := reflect.TypeOf(obj)
	v := reflect.ValueOf(obj)

	var data = make(map[string]interface{})
	for i := 0; i < t.NumField(); i++ {
		data[t.Field(i).Name] = v.Field(i).Interface()
	}
	return data
}

// MD5加密函数
// @str          string          需要进行加密的字符串
func UserMD5(usr string, pwd string, salt string) string {
	// var salt = "1qazxsw2"
	var str = usr + salt + pwd
	var cipherStr []byte
	iteration := 2
	h := md5.New()
	h.Write([]byte(str))
	cipherStr = h.Sum(nil)
	for i := 1; i < iteration; i++ {
		h2 := md5.New()
		h2.Write(cipherStr)
		cipherStr = h2.Sum(nil)
	}
	h.Write([]byte(pwd))
	return hex.EncodeToString(cipherStr)
}
func MyMD5(str string) string {
	h := md5.New()
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum(nil))
}

// 时间戳格式化
// @timestamp            int             时间戳
// @format               string          时间格式，如："2006-01-02 15:04:05"
func TimestampFormat(timestamp int64, format ...string) string {
	formats := "2006-01-02 15:04:05"
	if len(format) > 0 {
		formats = format[0]
	}
	return time.Unix(int64(timestamp), 0).Format(formats)
}
func UTCTransLocal(utcTime string) string {
	t, _ := time.Parse("2006-01-02T15:04:05.000+08:00", utcTime)
	return t.Local().Format("2006-01-02 15:04:05")
}
func LocalTransUTC(localTime string) string {
	t, _ := time.ParseInLocation("2006-01-02 15:04:05", localTime, time.Local)
	return t.UTC().Format("2006-01-02T15:04:05.000+08:00")
}
func Decimal(value float64) float64 {
	value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", value), 64)
	return value
}
func UndifinedTimeToStr(t1 string) time.Time {
	//时间转换的模板，golang里面只能是 "2006-01-02 15:04:05" （go的诞生时间）
	timeTemplate1 := "2006-01-02 15:04:05" //常规类型
	timeTemplate3 := "2006-01-02"          //其他类型
	// ======= 将时间字符串转换为时间 =======
	stamp, err := time.ParseInLocation(timeTemplate1, t1, time.Local) //使用parseInLocation将字符串格式化返回本地时区时间
	if err != nil {
		stamp, _ = time.ParseInLocation(timeTemplate3, t1, time.Local)
	}
	return stamp
}

// 字符串转时间格式
// @str            string             时间字符串
// @format               string          时间格式，如："2006-01-02 15:04:05"
func String2Time(str string, format ...string) time.Time {
	formats := "2006-01-02 15:04:05"
	if len(format) > 0 {
		formats = format[0]
	}
	time, _ := time.Parse(formats, str)
	return time
}

func DataString2Time(str string, format ...string) time.Time {
	formats := "2006-01-02"
	if len(format) > 0 {
		formats = format[0]
	}
	time, _ := time.Parse(formats, str)
	return time
}
func GetFirstDateOfWeek() (weekMonday string) {
	now := time.Now()

	offset := int(time.Monday - now.Weekday())
	if offset > 0 {
		offset = -6
	}

	weekStartDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
	weekMonday = weekStartDate.Format("2006-01-02")
	return
}

/*
*
获取上周的周一日期
*/
func GetLastWeekFirstDate() (weekMonday string) {
	thisWeekMonday := GetFirstDateOfWeek()
	TimeMonday, _ := time.Parse("2006-01-02", thisWeekMonday)
	lastWeekMonday := TimeMonday.AddDate(0, 0, -7)
	weekMonday = lastWeekMonday.Format("2006-01-02")
	return
}
func GetNextWeekFirstDate() (weekMonday string) {
	thisWeekMonday := GetFirstDateOfWeek()
	TimeMonday, _ := time.Parse("2006-01-02", thisWeekMonday)
	lastWeekMonday := TimeMonday.AddDate(0, 0, 7)
	weekMonday = lastWeekMonday.Format("2006-01-02")
	return
}
func GetNextWeekLastDate() (weekMonday string) {
	thisWeekMonday := GetFirstDateOfWeek()
	TimeMonday, _ := time.Parse("2006-01-02", thisWeekMonday)
	lastWeekMonday := TimeMonday.AddDate(0, 0, 14)
	weekMonday = lastWeekMonday.Format("2006-01-02")
	return
}

// 将字符串或者其他可转化数字的内容格式化成int数字类型返回
//
//	a            interface{}         需要转化成数字的内容
func Interface2Int(a interface{}) int {
	i, _ := strconv.Atoi(fmt.Sprintf("%v", a))
	return i
}
func String2Int(a string) int {
	i, _ := strconv.Atoi(a)
	return i
}
func String2Int64(a string) int64 {
	i, _ := strconv.Atoi(a)
	return int64(i)
}
func Int642String(a int64) string {
	return strconv.FormatInt(a, 10)
}
func Int2String(a int) string {
	return strconv.Itoa(a)
}

func Uint642String(a uint64) string {
	return strconv.Itoa(int(a))
}

func Uint2String(a uint) string {
	return strconv.Itoa(int(a))
}

func Interface2Int64(a interface{}) int64 {
	i, _ := strconv.ParseInt(fmt.Sprintf("%v", a), 10, 64)
	return i
}
func Int2Int64(a int) int64 {
	i := int64(a)
	return i
}

// 生成url链接
//
//	prefix              前缀
//	params              参数
//
// @return           urlstr              返回组装后的url
func BuildURL(prefix string, params ...interface{}) (urlstr string) {
	var (
		l   int
		url []string
	)
	url = append(url, "/"+strings.Trim(prefix, "/"))
	l = len(params)
	if l != (l/2)*2 {
		l = (l / 2) * 2
	}
	if l > 0 {
		for i := 0; i < l; {
			k := fmt.Sprintf("%v", params[i])
			v := fmt.Sprintf("%v", params[i+1])
			if len(k) > 0 && v != "0" {
				url = append(url, fmt.Sprintf("%v/%v", k, v))
			}
			i += 2
		}
	}
	urlstr = strings.TrimRight(strings.Join(url, "/"), "/")
	//fmt.Println("BuildURL:", prefix, params, len(params), url)
	return
}
func GetHourDiffer(start_time, end_time string) int64 {
	var hour int64
	t1, err := time.ParseInLocation("2006-01-02 15:04:05", start_time, time.Local)
	t2, err := time.ParseInLocation("2006-01-02 15:04:05", end_time, time.Local)
	if err == nil && t1.Before(t2) {
		diff := t2.Unix() - t1.Unix() //
		hour = diff / 3600
		return hour
	} else {
		return hour
	}
}

// 图片文件信息
type Info struct {
	Width, Height int    //图片宽高
	Size          int64  //图片文件大小
	Md5           string //图片md5
	ModTime       int    //图片修改时间戳
	Ext           string //图片后缀
}

// 判断文件路径判断文件是否是符合要求的图片格式，jpeg,jpg,gif,png,bmp,tif,tiff
// @path         string          文件路径
func IsImage(path string) bool {
	slice := strings.Split(path, ".")
	ext := strings.ToLower(strings.TrimSpace(slice[len(slice)-1]))
	exts := map[string]string{"jpeg": "jpeg", "jpg": "jpg", "gif": "gif", "png": "png", "bmp": "bmp", "tif": "tif", "tiff": "tiff"}
	_, ok := exts[ext]
	return ok
}
func GetFileExt(fileName string) string {
	fileitem := strings.Split(fileName, ".")
	ext := strings.ToLower(fileitem[len(fileitem)-1])
	return ext
}

// 获取文件的MD5
// @path         string          文件路径
func FileMd5(path string) (string, error) {
	var md5str string
	var err error
	var file *os.File
	file, err = os.Open(path)
	defer file.Close()
	if err != nil {
		return md5str, err
	}
	md5h := md5.New()
	_, err = io.Copy(md5h, file)
	if err == nil {
		md5str = fmt.Sprintf("%x", md5h.Sum(nil))
	}
	return md5str, err
}
func BigFileMd5(path string) (string, error) {
	var filechunk float64 = 8192
	file, err := os.Open(path)

	if err != nil {
		panic(err.Error())
	}

	defer file.Close()

	// calculate the file size
	info, _ := file.Stat()

	filesize := info.Size()

	blocks := uint64(math.Ceil(float64(filesize) / float64(filechunk)))

	hash := md5.New()

	for i := uint64(0); i < blocks; i++ {
		blocksize := int(math.Min(filechunk, float64(filesize-int64(float64(i)*filechunk))))
		buf := make([]byte, blocksize)

		file.Read(buf)
		io.WriteString(hash, string(buf)) // append into the hash
	}

	return string(hash.Sum(nil)), err
}

// 根据字符串后缀，比如根据文件路径获取后缀等
// @str          string          字符串或者文件路径
// @seg          string          分隔符
func GetSuffix(str, seg string) string {
	slice := strings.Split(str, seg)
	l := len(slice)
	if l > 1 {
		return slice[(l - 1)]
	}
	return ""
}

// 将interface{}转为字符串，适合bool，数字等
// @v            interface{}         需要转化为字符串的值
func Interface2String(v interface{}) string {
	return fmt.Sprintf("%v", v)
}

func RemoveRepeatedElement(tags string) (newtags string) {
	arr := strings.Split(tags, ",")
	newArr := make([]string, 0)

	for i := 0; i < len(arr); i++ {
		repeat := false
		if arr[i] == "" {
			continue
		}
		for j := i + 1; j < len(arr); j++ {
			if arr[i] == arr[j] || (arr[j] == "") || (arr[i] == "") {
				repeat = true
				break
			}
		}
		if !repeat {
			newArr = append(newArr, arr[i])
		}
	}
	return strings.Replace(strings.Trim(fmt.Sprint(newArr), "[]"), " ", ",", -1)
}

// 整型计算
func CalcInt(num1 interface{}, oper string, num2 interface{}) int {
	val := 0
	n1 := Interface2Int(num1)
	n2 := Interface2Int(num2)

	switch oper {
	case "+":
		val = n1 + n2
	case "-":
		val = n1 - n2
	case "*":
		val = n1 * n2
	case "%":
		if n2 != 0 {
			val = n1 % n2
		}
	case "/":
		if n2 != 0 {
			val = n1 / n2
		}
	}
	return val
}

// 压缩svg文件
//
//	file			需要压缩的svg文件
//
// @return			err				错误
func CompressSvg(file string) (err error) {
	var b []byte
	if b, err = ioutil.ReadFile(file); err == nil {
		str := string(b)
		str = strings.Replace(str, "\t", "", -1)
		str = strings.Replace(str, "\n", "", -1)
		str = strings.Replace(str, "\r", "", -1)
		//去除标签之间的空格，如果是存在代码预览的页面，不要替换空格，否则预览的代码会错乱
		r, _ := regexp.Compile(">\\s{1,}<")
		str = r.ReplaceAllString(str, "><")
		//多个空格替换成一个空格
		r2, _ := regexp.Compile("\\s{1,}")
		str = r2.ReplaceAllString(str, " ")
		err = ioutil.WriteFile(file, []byte(str), os.ModePerm)
	}
	return
}

// 文档评分处理
// score：文档评分
// IsScore:是否返回处理后的评分，true：返回评分，如“4.5”，false返回css的星，如"45"
func StarVal(score int, IsScore bool) string {
	if IsScore {
		return fmt.Sprintf("%1.1f", float32(score)/10000.0)
	}
	return fmt.Sprintf("%d", score/1000)
}

// 将字符串切片转成interface切片
func StringSliceToInterfaceSlice(slice []string) (ret []interface{}) {
	for _, v := range slice {
		ret = append(ret, v)
	}
	return ret
}

// 将字符串切片数组转成map
func StringSliceToMap(slice []string) (maps map[string]string) {
	maps = make(map[string]string)
	for _, v := range slice {
		maps[v] = v
	}
	return maps
}

// url请求处理
func UrlEscape(str string) string {
	return strings.TrimSpace(url.QueryEscape(strings.Replace(str, "/", " ", -1)))
}

// 高亮，主要用于搜索结果高亮
func HeightLight(title string, words []string) template.HTML {
	//注意：不能直接高亮，比如title里面有span标签作为关键字的时候就出现问题了
	for _, wd := range words {
		r, _ := regexp.Compile(fmt.Sprintf("(?i:%v)", wd))
		title = r.ReplaceAllString(title, fmt.Sprintf("<wenku.it>%v</wenku.it>", wd))
	}
	for _, wd := range words {
		r, _ := regexp.Compile(fmt.Sprintf("(?i:%v)", fmt.Sprintf("<wenku.it>%v</wenku.it>", wd)))
		title = r.ReplaceAllString(title, fmt.Sprintf(`<span class="text-danger">%v</span>`, wd))
	}
	return template.HTML(title)
}

// 字符串截取
func SubStr(str interface{}, start, length int) string {
	v := fmt.Sprintf("%v", str)
	if start < 0 {
		start = 0
	}
	slice := strings.Split(v, "")
	l := len(slice)
	if l == 0 || start > l {
		return ""
	}
	if start+length+1 > l {
		return strings.Join(slice[start:], "")
	}
	return strings.Join(slice[start:length], "")
}

//
////给SVG加文字水印
////			svgfile			svg文件
////			text			水印文字
////@return			err				nil时表示添加水印成功
//func WatermarkByText(svgfile, text string) (err error) {
//	return
//}

// 数字变化范围
//
//	val             int         需要处理的参数数字
//	min             int         最小值
//	max             int         最大值
//
// @return                           int         返回最大值与最小值之间的值
func NumberRange(val, min, max int) int {
	if val < min {
		return min
	}
	if val > max {
		return max
	}
	return val
}

// 首字母大写
func UpperFirst(str string) string {
	if len(str) > 0 {
		strings.Replace(str, str[0:1], strings.ToUpper(str[0:1]), 1)
	}
	return str
}

// 删除切片中的指定key，并返回
func DeleteSlice(slice []string, keys ...string) []string {
	if len(keys) == 0 {
		return slice
	}

	for _, key := range keys {
		var tmpSlice []string
		for _, item := range slice {
			if item != key {
				tmpSlice = append(tmpSlice, item)
			}
		}
		slice = tmpSlice
	}

	return slice
}
func ComputeFileMD5(file io.Reader) string {
	md5h := md5.New()
	io.Copy(md5h, file)
	return fmt.Sprintf("%x", md5h.Sum(nil))
}

// CreateCaptcha 生成随机数
// n：生成的位数
func CreateCaptcha(n int) string {
	code := ""
	rand.Seed(time.Now().Unix())
	for i := 0; i < n; i++ {
		code = fmt.Sprintf("%s%d", code, rand.Intn(10))
	}
	return code
}
func ToInterfaceSlice(slice interface{}) []interface{} {
	s := reflect.ValueOf(slice)
	if s.Kind() != reflect.Slice {
		panic("InterfaceSlice() given a non-slice type")
	}

	ret := make([]interface{}, s.Len())

	for i := 0; i < s.Len(); i++ {
		ret[i] = s.Index(i).Interface()
	}

	return ret
}
func IsChinese(str string) bool {
	var count int
	for _, v := range str {
		if unicode.Is(unicode.Han, v) {
			count++
			break
		}
	}
	return count > 0
}

func HtmlToMarkdown(html string) (string, error) {
	var err error
	converter := md.NewConverter("", true, nil)

	markdown, err := converter.ConvertString(html)

	return markdown, err

}

// 判断第几周
func NumberOfNowWeekInMonth() int {
	now := time.Now()
	_, w1 := time.Now().UTC().ISOWeek()
	_, w2 := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.UTC).UTC().ISOWeek()
	return w1 - w2 + 1
}

// 判断第几周
func NumberOfWeekInMonth(t time.Time) int {

	_, w1 := t.UTC().ISOWeek()
	_, w2 := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.UTC).UTC().ISOWeek()
	return w1 - w2 + 1
}

// 判断星期几
func WhichWeekDay() int {
	ts := time.Now()
	return int(ts.Weekday())
}

// 当月第一个周一
func FirstMonday(year int, month time.Month) int {
	t := time.Date(year, month, 1, 0, 0, 0, 0, time.UTC)
	return (8-int(t.Weekday()))%7 + 1
}

func Strval2String(value interface{}) string {
	// interface 转 string
	var key string
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	case time.Time:
		key = value.(time.Time).Format("2006-01-02 15:04:05")
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}
	return key
}

func StringListToIntList(src []string) (dest []int) {
	for _, v := range src {
		ds := String2Int(v)
		dest = append(dest, ds)
	}
	return dest
}

// DetermineUnit 根据金额的大小确定单位（元、万元、亿）
func DetermineUnit(amount float64) string {
	switch {
	case amount >= 100000000: // 大于等于1亿
		return "亿"
	case amount >= 10000: // 大于等于1万元
		return "万元"
	default:
		return "元"
	}
}

// ConvertToYuan 将金额转换为匹配的单位
func ConvertToYuan(amount float64, unit string, decimalPlaces int) (float64, string) {
	unitConversion := map[string]int64{
		"元":  1,
		"万元": 10000,
		"亿":  100000000,
	}
	if unit == "" {
		unit = DetermineUnit(amount)
	}
	fromValue, _ := decimal.NewFromFloat(float64(amount) / float64(unitConversion[unit])).Float64()
	result := math.Round(fromValue*math.Pow10(decimalPlaces)) / math.Pow10(decimalPlaces)
	return result, strconv.FormatFloat(result, 'f', -1, 64) + unit
}

// 判断字符串中是否存在特殊符号
func SpecialCharIsExist(str, specialChars string) bool {
	if specialChars == "" {
		specialChars = `{<>~!@#$%^*?/|:,;=\\'-+，。、；‘’【】、·！￥…&*（）—};` + "`" + "-"
	}
	specialCharsPattern := "[" + specialChars + "]"
	re := regexp.MustCompile(specialCharsPattern)

	// 检查字符串中是否包含特殊符号
	return re.MatchString(str)
}
func VerifyPhoneOk(phone string) bool {
	// 定义正则表达式
	// ^1 表示以1开头
	// [3-9] 表示第二位是3到9之间的数字
	// \d{9} 表示后面跟着9位数字
	// $ 表示字符串结束
	pattern := `^1[3-9]\d{9}$`

	// 编译正则表达式
	re := regexp.MustCompile(pattern)

	// 验证手机号
	return re.MatchString(phone)
}
